/**
    Copyright (C) 2011  Alexander Vollmer

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.jefb.service.impl;

import java.io.File;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.jefb.entity.DestinationEntity;
import org.jefb.entity.FileDestEntity;
import org.jefb.entity.FileEntity;
import org.jefb.service.ICommonPersistenceService;
import org.jefb.service.IFileRegisterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class FileRegisterService implements IFileRegisterService {
	
	/**
	 * services
	 */
	
	private static Logger log = LoggerFactory.getLogger(FileRegisterService.class);
	
	//business services
	@Autowired
	private ICommonPersistenceService commonPersistenceService;

	public void registerFiles() {
		log.info("...registering files from:", this.getClass());
		
		File outbox = new File("/");
		if (outbox.exists() && outbox.isDirectory()) {
			File[] listFiles = outbox.listFiles();
			for (File file : listFiles) {
				if (file.isFile()) {
					FileEntity fileEntity = new FileEntity();
					fileEntity.setName(file.getName());
					fileEntity.setSize(file.length());
					List<FileEntity> findByExample = commonPersistenceService
							.findByExample(fileEntity,
									"description", "md5Hash",
									"registrationTime");
					if (findByExample != null && findByExample.size() < 1) {
						fileEntity.setRegistrationTime(new Date());
						commonPersistenceService.persistEntity(fileEntity);
					}
				}
			}
		} else {
			// TODO handle it
		}
	}
	
	/**
	 * Register all files found in given directory.
	 */
	public void registerFiles(FileEntity dirEntity){
		//recursive parse and register all files
		//String fullDirName = config.getBaseDir()+dirEntity.getName();
		String fullDirName = dirEntity.getName();
		File dir = new File(fullDirName);
		registerFile(dir, dirEntity.getDestinations(), dirEntity.getWorkspace());
	}
	
	/**
	 * Register file.
	 * @param file
	 * @param destinations
	 * @param workspace 
	 */
	private void registerFile(File file, Collection<DestinationEntity> destinations, String workspace){
		if(file.exists()){
			if(file.isFile()){
				assignForTransmission(file, destinations, workspace);
			}else{
				for(File listedFile:file.listFiles()){
					registerFile(listedFile, destinations, workspace);
				}
			}
		}
	}

	/**
	 * Assigns file for transmission for given destinations.
	 * @param file
	 * @param destinations
	 * @param workspace 
	 */
	private void assignForTransmission(File file, Collection<DestinationEntity> destinations, String workspace) {
		String fileName = file.getName();
		//create example to check if file already registered in the DB
		FileEntity example = new FileEntity();
		example.setName(fileName);
		//example.setPath(JefbUtils.extractPath(file.getAbsolutePath(), fileName, workspace, config.getBaseDir()));
		example.setWorkspace(workspace);
		List<FileEntity> foundFileEntities = commonPersistenceService
		.findAllByExample(example);
		if(foundFileEntities.isEmpty()){
			//add all assigned destination and register file
			example.getDestinations().addAll(destinations);
			example.setCreationTime(new Date());
			example.setLastUpdateTime(new Date());
			example.setSize(file.length());
			commonPersistenceService.persistEntity(example);
		}else{
			for(FileEntity fileEntity:foundFileEntities){
				//add only missing destinations and update registered file
				addNewDestiantions(fileEntity.getDestinations(), destinations);
				commonPersistenceService.updateEntity(fileEntity);
			}
		}
	}

	private void addNewDestiantions(Collection<DestinationEntity> assignedDestinations,
			Collection<DestinationEntity> newDestinations) {
		for(DestinationEntity newDestination:newDestinations){
			if(!assignedDestinations.contains(newDestination)){
				assignedDestinations.add(newDestination);
			}
		}
	}



	public void cleanUpInbox() {

	}

	public void cleanUpOutbox() {
		// TODO Auto-generated method stub
	}

	public FileEntity registerFile(FileEntity fileEntity) {
		commonPersistenceService.updateEntity(fileEntity);
		List<FileEntity> findByExample = commonPersistenceService
		.findByExample(fileEntity,
				"description", "md5Hash",
				"registrationTime");
		if(!findByExample.isEmpty()){
			return findByExample.get(0);
		}
		return null;
	}

	public FileEntity findFileByName(String name, String storageName) {
		FileEntity fileEntity = new FileEntity();
		fileEntity.setName(name);
		fileEntity.setStorageName(storageName);
		List<FileEntity> findByExample = commonPersistenceService
		.findByExample(fileEntity,
				"description", "md5Hash",
				"registrationTime");
		if(!findByExample.isEmpty()){
			return findByExample.get(0);
		}
		return null;
	}
	
	public List<FileDestEntity> loadAssignedFiles(){
		return commonPersistenceService.findAll(FileDestEntity.class);
	}

	@Transactional(readOnly=false,propagation = Propagation.REQUIRED)
	public void assignFileToDestination(FileEntity file,
			DestinationEntity destination) {
		commonPersistenceService.refresh(file);
		commonPersistenceService.refresh(destination);
		
		file.getDestinations().add(destination);
		commonPersistenceService.updateEntity(file);
		commonPersistenceService.updateEntity(destination);
		commonPersistenceService.flush();
	}

	public void setCommonPersistenceService(ICommonPersistenceService commonPersistenceService) {
		this.commonPersistenceService = commonPersistenceService;
	}

	public ICommonPersistenceService getCommonPersistenceService() {
		return commonPersistenceService;
	}

}
